/*
 *  OutputControl.mm
 *  NXTFace
 *
 *  Created by David Giovannini on 8/23/06.
 *  Copyright 2006 Software by Jove. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#import "NxtOutput.h"

#include "SBJ/NXT/Output.h"
#include "SBJ/NXT/Device.h"

@implementation NxtOutput

// Initialization

+ (void)initialize
{
    NSArray* keys = [ NSArray arrayWithObjects:
         @"Port", @"Power", @"On", @"State", nil];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"InMotion" ];
		
	keys = [ NSArray arrayWithObjects: @"Port", nil ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"Name" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"Power" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"On" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"UsesBrake" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"Regulated" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"Regulation" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"TurnRatio" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"State" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"TachoLimit" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"Tacho" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"BlockTacho" ];
    [ self setKeys:keys triggerChangeNotificationsForDependentKey: @"RotateTacho" ];
}

-(id) initOutputOf: (NxtDevice*)theDevice on: (unsigned char)port
{
	m_device = theDevice;
	m_output = &( [ m_device deviceRef ]->getOutput( (SBJ::NXT::OutputPort)port ) );
	return [ super init ];
}

- (void) dealloc
{
	[ super dealloc ];
}

// KVC Read-Only Attributes

- (unsigned char) Port
{
	return m_output->getPort();
}

- (NSString*) Name
{
	return [ NSString stringWithFormat: @"%c", 'A' + m_output->getPort() ];
}

- (BOOL) InMotion
{
	return m_output->isInMotion();
}

- (long) Tacho
{
	return m_output->getTachoCount();
}

- (long) BlockTacho
{
	return m_output->getBlockTachoCount();
}

- (long) RotateTacho
{
	return m_output->getRotateTachoCount();
}

// KVC Attributes

- (char) Power
{
	return m_output->getPower();
}

- (BOOL) On
{
	return m_output->getMotorMode( SBJ::NXT::mode_on );
}

- (BOOL) UsesBrake
{
	return m_output->getMotorMode( SBJ::NXT::mode_brake );
}

- (BOOL) Regulated
{
	return m_output->getMotorMode( SBJ::NXT::mode_regulated );
}

- (unsigned long) TachoLimit
{
	return m_output->getTachoLimit();
}

- (char) TurnRatio
{
	return m_output->getTurnRatio();
}

// KVC Read Attributes

- (void) setPower:(char)value
{
	m_output->setPower( value );
}

- (void) setOn:(BOOL)value
{
	if ( value )
		m_output->setMotorMode( SBJ::NXT::mode_on );
	else
		m_output->setMotorMode( SBJ::NXT::mode_none, SBJ::NXT::mode_on );
}

- (void) setUsesBrake:(BOOL)value
{
	if ( value )
		m_output->setMotorMode( SBJ::NXT::mode_brake );
	else
		m_output->setMotorMode( SBJ::NXT::mode_none, SBJ::NXT::mode_brake );
}

- (void) setRegulated:(BOOL)value
{
	if ( value )
		m_output->setMotorMode( SBJ::NXT::mode_regulated );
	else
		m_output->setMotorMode( SBJ::NXT::mode_none, SBJ::NXT::mode_regulated );
}

- (void) setTachoLimit:(unsigned long)value
{
	m_output->setTachoLimit( value );
}

- (void) setTurnRatio:(char)value
{
	m_output->setTurnRatio( value );
}

// Actions

- (void) start: (char)power
{
	m_output->start( power );
}

- (void) stopWith: (EStopWith)what
{
	m_output->stop( what == stop_brake ? true : false );
}

- (void) start: (double)power For: (double)duration Using: (EMotorUnit)unit Then: (EStopWith)stopMode
{
	SBJ::NXT::MotorUnit sbjUnit = SBJ::NXT::motorUnit_degrees;
	m_output->start( power, duration, sbjUnit, false );
}

- (void) reset: (BOOL)relative
{
	m_output->resetSensor( relative );
}

// Scriptability

- (NSScriptObjectSpecifier *)objectSpecifier
{
	NSScriptObjectSpecifier *containerRef = [ m_device objectSpecifier ];
	return [ [ [ NSIndexSpecifier allocWithZone: [ self zone ] ]
		initWithContainerClassDescription: [ containerRef keyClassDescription ] 
			containerSpecifier:containerRef key: @"Outputs" index: m_output->getPort() ] autorelease ];
}

- (void)scripterSaysStop:(NSScriptCommand*)command
{ 
    NxtOutput* directObj = [command evaluatedReceivers]; 
	
    NSNumber* p1 = [[command evaluatedArguments] valueForKey:@"with"]; 
	
    if (self != directObj) { 
        //[self returnError:errOSACantAssign string:@"Invalid pairing."]; 
        return; 
    } 
    [ self stopWith: (EStopWith)[ p1 longValue ] ]; 
} 

- (void)scripterSaysStart:(NSScriptCommand*)command
{ 
    NxtOutput* directObj = [command evaluatedReceivers]; 
    NSNumber* p1 = [[command evaluatedArguments] valueForKey:@"with"]; 
    if (self != directObj) { 
        //[self returnError:errOSACantAssign string:@"Invalid pairing."]; 
        return; 
    } 
    [ self start: [ p1 doubleValue ] ]; 
}

-(void)scripterSaysRun:(NSScriptCommand*)command
{
    NxtOutput* directObj = [command evaluatedReceivers]; 
    NSNumber* p1 = [[command evaluatedArguments] valueForKey:@"at"]; 
    NSNumber* p2 = [[command evaluatedArguments] valueForKey:@"for"]; 
    NSNumber* p3 = [[command evaluatedArguments] valueForKey:@"using"]; 
    NSNumber* p4 = [[command evaluatedArguments] valueForKey:@"then"]; 
    if (self != directObj) { 
        //[self returnError:errOSACantAssign string:@"Invalid pairing."]; 
        return; 
    } 
    [ self start: [ p1 intValue ] For: [ p2 doubleValue ] Using: (EMotorUnit)[ p3 intValue ] Then: (EStopWith)[ p4 intValue ] ]; 
}

@end
